﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Caching;
using VideoSeller.Business.Data;
using VideoSeller.Business.Data.Entities;
using VideoSeller.Business.Data.Enums;
using VideoSeller.Core.Interfaces;

namespace VideoSeller.Business.Models
{
	public class PostingModel : Repository<Posting>
	{
		private readonly FinanceModel _financeModel;
		private readonly ClientModel _clientModel;
		private readonly OnlineContentClaimModel _claimModel;
		private readonly IDatabaseSettingsProvider _databaseSettingsProvider;

		public PostingModel(FinanceModel financeModel, OnlineContentClaimModel claimModel, ClientModel clientModel, IDatabaseSettingsProvider databaseSettingsProvider)
		{
			_financeModel = financeModel;
			_claimModel = claimModel;
			_clientModel = clientModel;
			_databaseSettingsProvider = databaseSettingsProvider;
		}

		public void AddFinanceOperation(Finance finance, decimal value, FinanceOperation operation)
		{
			AddFinanceOperation(finance.UserId, value, operation);
		}

		public void AddFinanceOperation(Guid userId, decimal value, FinanceOperation operation, string comment = null)
		{
			var posting = new Posting
			{
				FinanceId = userId,
				Value = value,
				Operation = (short)operation,
				Date = DateTime.Now,
				Comment = comment
			};

			Insert(posting);

			_financeModel.UpdateTotal(userId, value, operation);
		}

		public void StartWithdraw(Finance finance, WithdrawType type, string data)
		{
			var posting = new Posting
			{
				FinanceId = finance.UserId,
				Value = finance.Total,
				Operation = (short)FinanceOperation.WithdrawRequest,
				Date = DateTime.Now,
				WithdrawType = (short)type,
				WithdrawData = data
			};

			Insert(posting);

            //var lastWithdraw = Table.Where(x => x.FinanceId == finance.UserId && x.Operation == (short)FinanceOperation.WithdrawCompleted).OrderByDescending(x => x.Date).FirstOrDefault();
            //var lastWithdrawDate = lastWithdraw != null ? lastWithdraw.Date : DateTime.MinValue;
            //var hasClaims = _claimModel.HasUserContentClaimsForLastTime(finance.UserId, lastWithdrawDate);
            //var syncObject = new WithdrawSyncObject
            //    {
            //        HasClaims = hasClaims,
            //        PostingId = posting.Id
            //    };

            //HttpRuntime.Cache.Insert("WithdrawTimer" + syncObject.PostingId, syncObject, null,
            //                            DateTime.Now.AddMinutes(_databaseSettingsProvider.WithdrawalTimer),
            //                            Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, CacheItemRemoved);
		}

		public void CacheItemRemoved(string key, object value, CacheItemRemovedReason reason)
		{
			var syncObject = value as WithdrawSyncObject;

			if (syncObject == null)
			{
				return;
			}

			if (_databaseSettingsProvider.SkipClaimsCheck || !syncObject.HasClaims)
			{
				CompleteWithdraw(syncObject.PostingId);
			}
		}

		public void CompleteNonClaimedWithdraw(int postingId)
		{
			var posting = Table.SingleOrDefault(x => x.Id == postingId);

			if (posting != null)
			{
				var client = _clientModel.GetClient(posting.FinanceId);
				var totalSum = client.OnlineContents.Where(x => x.Claims == 0).SelectMany(x => x.Paids).Sum(x => x.Value);
				var message = HttpContext.GetGlobalResourceObject("Withdraw", "WithdrawCompletedPartial", CultureInfo.CurrentUICulture);


				posting.Date = DateTime.Now;
				posting.Operation = (short)FinanceOperation.WithdrawCompletedPartial;
				posting.Value = totalSum;
				posting.Comment = message != null ? message.ToString() : "WithdrawCompletedPartial";

				SubmitAllChanges();

				_financeModel.UpdateTotal(posting.FinanceId, posting.Value, FinanceOperation.WithdrawCompletedPartial);
			}
		}

		public void CompleteWithdraw(int postingId)
		{
			var posting = Table.SingleOrDefault(x => x.Id == postingId);

			if (posting != null)
			{
				DataContext.Refresh(RefreshMode.OverwriteCurrentValues, posting);

				if (posting.OperationEnum == FinanceOperation.WithdrawCanceled || posting.OperationEnum == FinanceOperation.WithdrawCompleted)
				{
					return;
				}

				if (posting.OperationEnum == FinanceOperation.WithdrawCompletedPartial)
				{
					var client = _clientModel.GetClient(posting.FinanceId);
					posting.Value = client.OnlineContents.Where(x => x.Claims > 0).SelectMany(x => x.Paids).Sum(x => x.Value);
				}

				posting.Date = DateTime.Now;
				posting.Operation = (short) FinanceOperation.WithdrawCompleted;

				SubmitAllChanges();

				_financeModel.UpdateTotal(posting.FinanceId, posting.Value, FinanceOperation.WithdrawCompleted);
			}
		}

		public void CancelWithdraw(int postingId, string reason)
		{
			var posting = Table.SingleOrDefault(x => x.Id == postingId);

			if (posting != null)
			{
				posting.Date = DateTime.Now;
				posting.Operation = (short)FinanceOperation.WithdrawCanceled;
				posting.Comment = reason;

				SubmitAllChanges();
			}
		}

		public void PayForMeeting(Finance finance, int membersCount)
		{
			var price = _databaseSettingsProvider.MeetingPriceForMember * membersCount;
			var posting = new Posting
			{
				FinanceId = finance.UserId,
				Value = price,
				Operation = (short)FinanceOperation.OnlineContentAdvertisingPayment,
				Date = DateTime.Now
			};

			Insert(posting);

			_financeModel.UpdateTotal(finance.UserId, price, FinanceOperation.OnlineContentAdvertisingPayment);
		}
        public void PayForContentPublish(Finance finance, decimal moneyValue, int contentID)
        {
             
            var posting = new Posting
            {
                FinanceId = finance.UserId,
                Value = moneyValue,
                Operation = (short)FinanceOperation.BroadcastPayment,
                Comment = "Content "+contentID.ToString()+" publishing;",
                Date = DateTime.Now
            };
            
            Insert(posting);

            _financeModel.UpdateTotal(finance.UserId, moneyValue, FinanceOperation.BroadcastPayment);
        }

		public void DeleteAll(IEnumerable<Posting> items)
		{
			foreach (var item in items)
			{
				var entity = Table.SingleOrDefault(x => x.Id == item.Id);

				if (entity != null)
				{
					Table.DeleteOnSubmit(entity);
				}
			}

			SubmitAllChanges();
		}
        public ManyBalance getManyByPeriod(DateTime fromt, DateTime tot)
        {
            int mdt = (int)(tot - fromt).TotalDays;
           // var yz = Enumerable.Range(0, mdt).AsQueryable();
            //
            // IQueryable[] zs = new IQueryable[] {null, null, null, null };
            var r = Table.Where(m => m.Date >= fromt && m.Date < tot && m.Value != null);
            decimal fBroadcastPayment = 0;
            decimal fRefill = 0;
            decimal fWdCompleted = 0;
            decimal fOnlineContentPayment = 0;
            if (r != null)
            {
                try
                {
                    fBroadcastPayment = r.Where(m => m.Operation == (short)FinanceOperation.BroadcastPayment).Sum(m => m.Value);
                    fRefill = r.Where(m => m.Operation == (short)FinanceOperation.Refill).Sum(m => m.Value);
                    fWdCompleted = r.Where(m => m.Operation == (short)FinanceOperation.WithdrawCompleted).Sum(m => m.Value);
                    fOnlineContentPayment = r.Where(m => m.Operation == (short)FinanceOperation.OnlineContentPayment).Sum(m => m.Value);
                }
                catch
                {
                }
            }
            decimal totalfinace = _financeModel.GetAll().Sum(m => m.Total);
                //|| m.OperationEnum == FinanceOperation.WithdrawCompleted);
            ManyBalance n = new ManyBalance { BroadcastPayment=fBroadcastPayment, inMany =  fRefill, outMany = fWdCompleted, OnlineContentPayment = fOnlineContentPayment, sumCurrentMany = totalfinace};
            return n;
            
        }

        public  IQueryable  getVSMByPeriod(DateTime fromt, DateTime tot)
        {
            int mdt = (int)(tot - fromt).TotalDays;
            var yz = Enumerable.Range(0,mdt).AsQueryable();
            //
           // IQueryable[] zs = new IQueryable[] {null, null, null, null };
            var r = Table.Where(m => m.Date >= fromt && m.Date < tot);
            r = r.Where(m => m.OperationEnum == FinanceOperation.Refill || m.OperationEnum == FinanceOperation.WithdrawCompleted);
            var z = r.Select(m => new { vsm = m.Value, dt = m.Date.Date, tp = m.OperationEnum });
            var vsmi = z.GroupBy(m => m.dt).Select(y => new { vsm = y.Sum(m => m.vsm), dtt = y.Min(m => m.dt), tp = y.Min(m => m.tp) }).Where(m => m.tp == FinanceOperation.Refill);
            var vsm0 = z.GroupBy(m => m.dt).Select(y => new { vsm = y.Sum(m => m.vsm), dtt = y.Min(m => m.dt), tp = y.Min(m => m.tp) }).Where(m => m.tp == FinanceOperation.WithdrawCompleted);
            var aldates = from a in yz select new {fromt.Date.AddDays(a).Date};
            var u = from c in aldates join d in vsmi on c.Date equals d.dtt select new { dat = c.Date, vali = d.vsm };
            var u1 = from c in u join d in vsm0 on c.dat equals d.dtt select new { dat = c.dat, vali = c.vali, valo=d.vsm };
            return u1.AsQueryable();
        }
	}
}